<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="AnFZa" id="AnFZa"><span data-lake-id="ufc43b81d" id="ufc43b81d">典型回答</span></h1>
  <p data-lake-id="u6ffdfcb9" id="u6ffdfcb9"><br></p>
  <p data-lake-id="u6e779f69" id="u6e779f69"><br></p>
  <p data-lake-id="u7cc404f5" id="u7cc404f5"><span data-lake-id="ud658e6a9" id="ud658e6a9">先看上面的这个，了解下什么是InnoDB中的数据页。</span></p>
  <p data-lake-id="ud6e223d5" id="ud6e223d5"><span data-lake-id="u5730db09" id="u5730db09">​</span><br></p>
  <p data-lake-id="ufa5b19c7" id="ufa5b19c7"><span data-lake-id="u8f81b84a" id="u8f81b84a">InnoDB的数据页是InnoDB存储引擎中用于存储数据的基本单位，通常大小为16KB。B+树的每个节点都对应着一个数据页，包括根节点、非叶子节点和叶子节点。B+树通过节点之间的指针连接了不同层级的数据页，从而构建了一个有序的索引结构。</span></p>
  <p data-lake-id="u7c10343e" id="u7c10343e"><span data-lake-id="ud861c18c" id="ud861c18c">​</span><br></p>
  <p data-lake-id="u0471c033" id="u0471c033"><span data-lake-id="uf08e7a94" id="uf08e7a94">我们都是知道，B+树是按照索引字段建立的，并且在B+树中是有序的，假如有下面一个索引的数结构，其中的索引字段的值并不连续。</span></p>
  <p data-lake-id="u80b456d0" id="u80b456d0"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1691209336653-cd371e3f-4a0f-4a2f-9cfc-17bc7c056a14.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_21%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u527dfaae" id="u527dfaae"><br></p>
  <p data-lake-id="ue9eae950" id="ue9eae950"><span data-lake-id="u900d6038" id="u900d6038">假如，现在我们插入一个新的一条记录，他的索引值是3，那么他就要按照顺序插入到页20中，在索引值为1,2的记录的后面。而如果这个索引页已经满了，那么就需要触发一次页分裂。</span></p>
  <p data-lake-id="u640865b3" id="u640865b3"><span data-lake-id="uc712f312" id="uc712f312">​</span><br></p>
  <blockquote data-lake-id="uad1c70d5" id="uad1c70d5">
   <p data-lake-id="u3b190195" id="u3b190195"><strong><span data-lake-id="u09bc134d" id="u09bc134d">页分裂是指将该页面中的一部分索引记录移动到一个新的页面中，从而为新记录腾出空间。这样可以保持B+树的平衡和性能。</span></strong></p>
  </blockquote>
  <p data-lake-id="u2f8a1e6c" id="u2f8a1e6c"><span data-lake-id="u50833a38" id="u50833a38">​</span><br></p>
  <p data-lake-id="u1f12d9a8" id="u1f12d9a8"><span data-lake-id="ude9e9727" id="ude9e9727">以下，就是一次页分裂的过程：</span></p>
  <p data-lake-id="u94bc581e" id="u94bc581e"><span data-lake-id="ub100ee70" id="ub100ee70">​</span><br></p>
  <p data-lake-id="ubb13847e" id="ubb13847e"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1691209974023-b59ee310-e039-4d1b-990f-882c08c4bf22.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_21%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u6adb3944" id="u6adb3944"><span data-lake-id="u0194f4b2" id="u0194f4b2">​</span><br></p>
  <p data-lake-id="u62d33341" id="u62d33341"><span data-lake-id="u66f34291" id="u66f34291">那么，当我们向Innodb中添加数据的时候，如果索引是随机无序的，那么就会导致页分裂。而且分裂这个动作还可能会引起连锁反应，从叶子节点沿着树结构一路分裂到根节点。</span></p>
  <p data-lake-id="ub5121659" id="ub5121659"><span data-lake-id="u7b5eae65" id="u7b5eae65">​</span><br></p>
  <p data-lake-id="ucf17bd46" id="ucf17bd46"><span data-lake-id="uf448e4b6" id="uf448e4b6">有分裂，就会有合并。在InnoDB中，当索引页面中的索引记录删除后，页面可能会变得过于稀疏。这时，为了节省空间和提高性能，可能会触发</span><strong><span data-lake-id="u8b978613" id="u8b978613">叶合并</span></strong><span data-lake-id="u88ab169c" id="u88ab169c">操作。</span></p>
  <p data-lake-id="u389cbc72" id="u389cbc72"><span data-lake-id="ua217f0f3" id="ua217f0f3">​</span><br></p>
  <blockquote data-lake-id="u07c130c5" id="u07c130c5">
   <p data-lake-id="u19cfb145" id="u19cfb145"><strong><span data-lake-id="u919d9010" id="u919d9010">叶合并是指将两个相邻的索引页面合并成一个更大的页面，减少B+树的层级，从而提高查询性能。</span></strong></p>
  </blockquote>
  <p data-lake-id="u70b2b6bd" id="u70b2b6bd"><span data-lake-id="uc765e4aa" id="uc765e4aa">​</span><br></p>
  <p data-lake-id="u7fcdfa4a" id="u7fcdfa4a"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1691209988733-7632185f-cb6c-4587-b1e8-0299cf85611c.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_22%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="ua97791d7" id="ua97791d7"><br></p>
  <h1 data-lake-id="N5Zka" id="N5Zka"><span data-lake-id="u9ea751d6" id="u9ea751d6">扩展知识</span></h1>
  <p data-lake-id="u30c2be6f" id="u30c2be6f"><br></p>
  <h2 data-lake-id="QAWkG" id="QAWkG"><span data-lake-id="u86bb91ef" id="u86bb91ef">页分裂（合并）的危害</span></h2>
  <p data-lake-id="u8015ce99" id="u8015ce99"><br></p>
  <p data-lake-id="u7ed22a7d" id="u7ed22a7d"><span data-lake-id="u9955854d" id="u9955854d">首先，页分裂和合并是涉及大量数据移动和重组的操作。频繁进行这些操作会增加数据库的I/O负担和CPU消耗，影响数据库的整体性能。</span></p>
  <p data-lake-id="u2491fb51" id="u2491fb51"><span data-lake-id="uc42863d7" id="uc42863d7">​</span><br></p>
  <p data-lake-id="u202fd46a" id="u202fd46a"><span data-lake-id="udfffa7bd" id="udfffa7bd">分裂和合并可能导致B+树索引结构频繁调整，这个过程也会影响插入及删除操作的性能。</span></p>
  <p data-lake-id="u347c7b73" id="u347c7b73"><br></p>
  <p data-lake-id="u228e59e7" id="u228e59e7"><span data-lake-id="u82a943bf" id="u82a943bf">频繁的页分裂和合并可能会导致磁盘上存在较多的空间碎片，新分出的一个页一般会有很多空闲空间，使得数据库表占用更多的磁盘空间，而导致浪费。</span></p>
  <p data-lake-id="u222ba984" id="u222ba984"><br></p>
  <h2 data-lake-id="I1jsv" id="I1jsv"><span data-lake-id="ueddf4ec5" id="ueddf4ec5">如何避免页分裂</span></h2>
  <p data-lake-id="u61f56e52" id="u61f56e52"><br></p>
  <p data-lake-id="u80bbe451" id="u80bbe451"><br></p>
  <p data-lake-id="u463a4b76" id="u463a4b76"><br></p>
  <p data-lake-id="uc61bf00b" id="uc61bf00b"><span data-lake-id="u25c434a5" id="u25c434a5">在上面两篇中，我们介绍过，使用varchar或者使用UUID作为主键的话，都会导致页分裂。</span></p>
  <p data-lake-id="u6b772f2c" id="u6b772f2c"><span data-lake-id="ubad51a43" id="ubad51a43">​</span><br></p>
  <p data-lake-id="uf3ac79ab" id="uf3ac79ab"><span data-lake-id="u5e9fbfbb" id="u5e9fbfbb">所以，尽量选择使用自增的字段作为索引，尤其是主键索引，这样可以很大程度的避免页分裂。</span></p>
  <p data-lake-id="u672d24b0" id="u672d24b0"><span data-lake-id="ud2f449f0" id="ud2f449f0">​</span><br></p>
  <p data-lake-id="ud6fdabfa" id="ud6fdabfa"><span data-lake-id="u240d8332" id="u240d8332">如果要插入大量数据，尽量使用批量插入的方式，而不是逐条插入。这样可以减少页分裂的次数。</span></p>
  <p data-lake-id="u3ca11878" id="u3ca11878"><span data-lake-id="ucebcbc5a" id="ucebcbc5a">​</span><br></p>
  <p data-lake-id="u5bb476cc" id="u5bb476cc"><span data-lake-id="u7b1de751" id="u7b1de751">频繁删除操作可能导致页面过于稀疏，从而触发叶合并。所以，一般建议使用</span><strong><span data-lake-id="u2d50a048" id="u2d50a048">逻辑删除</span></strong><span data-lake-id="u3d5a268c" id="u3d5a268c">而不是物理删除。</span></p>
  <p data-lake-id="u2e2cca38" id="u2e2cca38"><span data-lake-id="ueea0c619" id="ueea0c619">​</span><br></p>
  <blockquote data-lake-id="ud08e5819" id="ud08e5819">
   <p data-lake-id="u4c0ea1f4" id="u4c0ea1f4"><span data-lake-id="ubdf3dde7" id="ubdf3dde7">逻辑删除：即在记录中添加一个标记来表示记录是否被删除(deleted = 0/1)，而不是真正地从数据库中删除记录。</span></p>
  </blockquote>
  <p data-lake-id="ue7c96300" id="ue7c96300"><br></p>
  <p data-lake-id="uf417ac31" id="uf417ac31"><span data-lake-id="u509a5bc4" id="u509a5bc4">我们当然还可以根据实际情况，适当调整InnoDB的配置参数，如页大小、填充因子、叶子页合并的阈值等，以优化数据库性能。</span></p>
  <p data-lake-id="ub45965bb" id="ub45965bb"><span data-lake-id="uaf68caf6" id="uaf68caf6">​</span><br></p>
  <p data-lake-id="u26843b21" id="u26843b21"><span data-lake-id="u5ee5b775" id="u5ee5b775">​</span><br></p>
 </body>
</html>